﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;

namespace Tilver.Data
{
    /// <summary>
    /// 数据库事务管理类
    /// </summary>
    public class TransactionManager //: IDisposable  继承IDisposable接口，用using()里会自动调用Dispose()方法释放资源
    {
        /// <summary>
        /// 事务级别
        /// </summary>
        public IsolationLevel IsolationLevel { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isolationLevel">事务级别，默认IsolationLevel.ReadCommitted</param>
        public TransactionManager(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
        {
            IsolationLevel = isolationLevel;
        }

        private readonly Dictionary<string, DbTransaction> _trans = new Dictionary<string, DbTransaction>();
        private List<DbConnection> _conns = new List<DbConnection>(3);
        private object _syncLock = new object();
        private bool _isOpened = false;
        /// <summary>
        /// 创建当前数据库操作事务，包含了创建和打开数据库连接
        /// </summary>
        /// <param name="database"></param>
        /// <returns></returns>
        internal DbTransaction GetTransaction(DbDataBase database)
        {
            DbTransaction tran = null;
            if (!_trans.ContainsKey(database.ConnectionString))
            {
                lock (_syncLock)
                {
                    if (!_trans.ContainsKey(database.ConnectionString))
                    {
                        DbConnection conn = database.CreateConnection();
                        conn.ConnectionString = database.ConnectionString;
                        database.OpenConnection(conn);
                        _conns.Add(conn);
                        tran = conn.BeginTransaction(IsolationLevel);
                        _trans.Add(database.ConnectionString, tran);
                        _isOpened = true;
                    }
                }
            }
            else
            {
                tran = _trans[database.ConnectionString];
            }
            return tran;
        }

        /// <summary>
        /// 提交事务，同时也关闭数据库连接
        /// </summary>
        public void Commit()
        {
            if (_isOpened && _trans.Count > 0)
            {
                try
                {
                    foreach (DbTransaction tran in _trans.Values)
                    {
                        tran.Commit();
                    }
                }
                finally
                {
                    //关闭数据库连接
                    foreach (var dbConnection in _conns)
                    {
                        //if (tran.Connection != null && tran.Connection.State != ConnectionState.Closed)
                        //{
                        //    tran.Connection.Close();
                        //}
                        dbConnection.Close();
                    }
                }
                _isOpened = false;
            }
            else
            {
                throw new Exception("没有创建事务或事物对象没有使用。");
            }
        }

        /// <summary>
        /// 回滚事务，同时也关闭数据库连接
        /// </summary>
        public void Rollback()
        {
            if (_isOpened && _trans.Count > 0)
            {
                try
                {
                    foreach (DbTransaction tran in _trans.Values)
                    {
                        tran.Rollback();
                    }
                }
                finally
                {
                    foreach (DbConnection conn in _conns)
                    {
                        conn.Close();
                    }
                }
                //foreach (DbTransaction tran in _trans.Values)
                //{
                //    tran.Rollback();
                //    //关闭数据库连接
                //    if (tran.Connection != null && tran.Connection.State != ConnectionState.Closed)
                //    {
                //        tran.Connection.Close();
                //    }
                //}
                _isOpened = false;
            }
            else
            {
                throw new Exception("没有创建事务或事物对象没有使用。");
            }
        }

        #region IDisposable
        private bool _disposed = false;

        /// <summary>
        /// 请显示调用Commit()或Rollback()释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            // 必须显示调用Commit()或Rollback()释放资源
            if (!_disposed)
            {
                //if (disposing) { }
                try
                {
                    if (_isOpened && _trans != null && _trans.Count > 0)
                    {
                        Rollback();
                    }
                }
                catch
                {
                    if (disposing) throw;
                }
                _disposed = true;
            }
        }
        /// <summary>
        /// 析构函数
        /// </summary>
        ~TransactionManager()
        {
            Dispose(false);
        }
        #endregion
    }
}
